package org.catspaw.cherubim.persistence.hibernate;

import java.net.URL;

import org.catspaw.cherubim.persistence.transaction.TransactionResourceLocal;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public final class HibernateSessionFactoryUtils {

	private static final String	CONFIG_FILE_LOCATION			= "hibernate.cfg.xml";
	private static final String	ANNOTATION_CONFIGURATION_CLASS	= "org.hibernate.cfg.AnnotationConfiguration";
	private static final String	SESSION_KEY						= Session.class.getName();
	private static String		configFile						= CONFIG_FILE_LOCATION;

	private HibernateSessionFactoryUtils() {
	}

	public static Session getSession(boolean allowCreate)
			throws HibernateException {
		Session session = (Session) TransactionResourceLocal.getResource(SESSION_KEY);
		if (session == null) {
			if (allowCreate) {
				try {
					session = SessionFactoryHolder.sessionFactory
							.getCurrentSession();
				} catch (HibernateException e) {
					session = SessionFactoryHolder.sessionFactory.openSession();
				}
				TransactionResourceLocal.bindResource(SESSION_KEY, session);
				return session;
			}
		} else if (!session.isOpen()) {
			throw new IllegalStateException(
					"the session on current thread was closed");
		}
		return session;
	}

	public static Session getSession() throws HibernateException {
		return getSession(true);
	}

	public static Session getCurrentSession() throws HibernateException {
		return getSession(false);
	}

	public static Session openSession() throws HibernateException {
		return SessionFactoryHolder.sessionFactory.openSession();
	}

	public static synchronized void rebuildSessionFactory() {
		SessionFactoryHolder.configuration = buildConfiguration();
		SessionFactoryHolder.sessionFactory = SessionFactoryHolder.configuration
				.buildSessionFactory();
	}

	private static Configuration buildConfiguration() {
		URL url = HibernateSessionFactoryUtils.class.getClassLoader()
				.getResource(configFile);
		return createConfiguration().configure(url);
	}

	private static Configuration createConfiguration() {
		try {
			Class<?> clazz = Class.forName(ANNOTATION_CONFIGURATION_CLASS);
			return (Configuration) clazz.newInstance();
		} catch (ClassNotFoundException e) {
		} catch (InstantiationException e) {
		} catch (IllegalAccessException e) {
		}
		return new Configuration();
	}

	public static void closeCurrentSession() throws HibernateException {
		Session session = (Session) TransactionResourceLocal.getResource(SESSION_KEY);
		TransactionResourceLocal.unbindResource(SESSION_KEY);
		if (session != null && session.isOpen()) {
			session.close();
		}
	}

	public static SessionFactory getSessionFactory() {
		return SessionFactoryHolder.sessionFactory;
	}

	public static void setConfigFile(String configFile) {
		HibernateSessionFactoryUtils.configFile = configFile;
	}

	public static Configuration getConfiguration() {
		return SessionFactoryHolder.configuration;
	}

	private static class SessionFactoryHolder {

		private static Configuration	configuration	= buildConfiguration();
		private static SessionFactory	sessionFactory	= configuration
																.buildSessionFactory();
	}
}
